package blackstar.performance.transform.instrutment;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;

import blackstar.performance.InvokePerformance;

/**
 * @author RayWoo (ayufox@gmail.com)
 * 
 */
public class InvokePerformanceMethodAdapter extends
		AbstractPerformanceMethodAdapter
{
	private final static int MONITOR_LOCAL = 2; // 需要2个位置的local空间记录方法执行开始时间
	private final static int MONITOR_STACK = 6; // 最少需要的栈大小,包括2个string引用+1个long值(2个位置)+1个异常引用/2个返回值(譬如long)

	private int localIndex = 0; // 需要维持一个本地变量记录开始时间,这里是该变量的偏移,在visitMaxs的时候计算实际偏移

	public InvokePerformanceMethodAdapter(String className, String methodName,
			int access, String desc, MethodVisitor mv)
	{
		super(className, methodName, access, desc, mv);
	}

	public void visitMaxs(int maxStack, int maxLocals)
	{
		super.visitMaxs(Math.max(MONITOR_STACK, maxStack), maxLocals
				+ MONITOR_LOCAL);
	}

	protected void addBeginInvoke()
	{
		// long time = System.nanoTime();
		localIndex = newLocal(Type.LONG_TYPE);
		mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "nanoTime", "()J");
		mv.visitVarInsn(LSTORE, localIndex);
	}

	protected void addEndInvoke()
	{
		// long time = System.nanoTime() - time;
		mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "nanoTime", "()J");
		mv.visitVarInsn(LLOAD, localIndex);
		mv.visitInsn(LSUB);
		mv.visitVarInsn(LSTORE, localIndex);

		// blackstar.performance.InvokePerformance.invokeMethod(className, methodName, time);
		mv.visitLdcInsn(this.className);
		mv.visitLdcInsn(this.methodName);
		mv.visitVarInsn(LLOAD, localIndex);
		mv.visitMethodInsn(INVOKESTATIC, InvokePerformance.CLASS_NAME,
				InvokePerformance.INVOKE_METHOD,
				InvokePerformance.METHOD_SYNTAX);
	}
}
